package com.cloud.little.config.log;


import com.alibaba.fastjson.JSONObject;
import com.cloud.little.config.util.WebUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.Map;

/**
 * @ Author     ：熊荣健
 * @ Date       ：Created in 2020.08.14
 * @ Description：全局日志统一获取
 * @ Modified By：
 * @Version:
 */
@Aspect
@Component
public class WebLogAspect {


    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    //要处理的方法，包名+类名+方法名  要注意子包在子包等要多加个*
    @Pointcut("execution(public * com.cloud.little.controller.*.*.*(..))")
    public void cut() {
    }

    @Before("cut()")//在调用上面 @Pointcut标注的方法前执行以下方法
    public void doBefore(JoinPoint joinPoint) throws Throwable {//用于获取类方法
    }

    @After("cut()")//无论Controller中调用方法以何种方式结束，都会执行
    public void doAfter() throws Throwable {
    }

    @Around("cut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {


        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        logger.info("《===============================开始记录=====================================》");

        //url
        logger.info("请求的接口 ：" + request.getRequestURI());
        //method
        logger.info("请求的方法 ：" + request.getMethod());
        //ip
        logger.info("用户IP ： " + request.getRemoteAddr());
        //类方法
        logger.info("被访问类的全路径 ：" + joinPoint.getSignature().getDeclaringTypeName() + '.' + joinPoint.getSignature().getName());//获取类名及类方法

        StringBuilder sb = new StringBuilder();
        //requestParam参数
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String parameter = parameterNames.nextElement();
            String value = request.getParameter(parameter);
            sb.append(parameter).append("=").append(value).append("  ");
        }
        //requestBody的参数
        String body = WebUtil.getBody(request);
        logger.info("请求参数为{}", "   RequestParam:" + sb.toString() + "   RequestBody:" + body);
        //动态修改其参数
        //注意，如果调用joinPoint.proceed()方法，则修改的参数值不会生效，必须调用joinPoint.proceed(Object[] args)
        Object result = joinPoint.proceed();
        logger.info("响应结果为{}", JSONObject.toJSONString(result));
        logger.info("《===============================结束记录=====================================》");

        //如果这里不返回result，则目标对象实际返回值会被置为null
        return result;
    }

    @AfterReturning(returning = "obj", pointcut = "cut()")//在调用上面 @Pointcut标注的方法后执行。用于获取返回值
    public void doAfterReturning(JoinPoint joinPoint, Object obj) throws Throwable {


    }


    /**
     * 请求参数拼装
     *
     * @param paramsArray
     * @return
     */
    private String argsArrayToString(Object[] paramsArray) {
        StringBuilder params = new StringBuilder();
        if (paramsArray != null && paramsArray.length > 0) {
            for (Object aParamsArray : paramsArray) {
                String jsonObj =  JSONObject.toJSONString(aParamsArray);
                params.append(jsonObj).append(" ");
            }
        }
        return params.toString().trim();
    }


    @AfterThrowing(pointcut = "cut()", throwing = "e")//切点在cut()
    public void handleThrowing(JoinPoint joinPoint, Exception e) {
//aop异常捕获，有些异常没办法捕获 controller类抛出的异常在这边捕获,但是controller之上的异常就没办法捕获


    }

    private String getParams(JoinPoint joinPoint, HttpServletRequest request) {
        String params;
        if ("POST".equals(request.getMethod())) {
            Object[] paramsArray = joinPoint.getArgs();

            params = argsArrayToString(paramsArray);
        } else {
            Map<?, ?> paramsMap = (Map<?, ?>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
            params = paramsMap.toString();
        }
        return params;
    }


}
